from datetime import datetime

from turbogears import identity
from turbogears.database import metadata, session

from sqlalchemy.ext.assignmapper import assign_mapper
from sqlalchemy import *


# The identity schema.
visits_table = Table('visit', metadata,
    Column('visit_key', String(40), primary_key=True),
    Column('created', DateTime, nullable=False, default=datetime.now),
    Column('expiry', DateTime))

visit_identity_table = Table('visit_identity', metadata,
    Column('visit_key', String(40), primary_key=True),
    Column('user_id', Integer, ForeignKey('tg_user.user_id'), index=True))

groups_table = Table('tg_group', metadata,
    Column('group_id', Integer, primary_key=True),
    Column('group_name', Unicode(16), unique=True),
    Column('display_name', Unicode(255)),
    Column('created', DateTime, default=datetime.now))

users_table = Table('tg_user', metadata,
    Column('user_id', Integer, primary_key=True),
    Column('user_name', Unicode(16), unique=True),
    Column('email_address', Unicode(255), unique=True),
    Column('display_name', Unicode(255)),
    Column('password', Unicode(40)),
    Column('first_name', Unicode(25)),
    Column('last_name', Unicode(25)),
    Column('created', DateTime, default=datetime.now))

permissions_table = Table('permission', metadata,
    Column('permission_id', Integer, primary_key=True),
    Column('permission_name', Unicode(16), unique=True),
    Column('description', Unicode(255)))

events_table = Table('events', metadata,
    Column('id', Integer, primary_key=True),
    Column('creator', Integer, ForeignKey('tg_user.user_id',
        ondelete="CASCADE")),
    Column('event_name', Unicode, nullable=False),
    Column('start_date', DateTime, nullable=False),
    Column('end_date', DateTime, nullable=False),
    Column('description', Unicode),
    Column('event_homepage', String),
    Column('event_picture', Binary),
    Column('privacy', Unicode(15)))
    
event_tags_table = Table('event_tags', metadata,
    Column('id', Integer, primary_key=True),
    Column('event_id', Integer, ForeignKey('events.id')),
    Column('tag_name', Unicode(25), nullable=False, unique=True))

venues_table = Table('venues', metadata,
    Column('id', Integer, primary_key=True),
    Column('venue_name', Unicode, nullable=False),
    Column('street_address', Unicode, nullable=False),
    Column('city', Unicode, nullable=False),
    Column('state', Unicode(2), nullable=False),
    Column('zip', Integer, nullable=False))

    
# association tables
events_tags_association = Table('events_tags_assoc', metadata,
    Column('tag_id', Integer, ForeignKey('event_tags.id')),
    Column('event_id', Integer, ForeignKey('events.id')))

event_venue_association = Table('events_venues', metadata,
    Column('event_id', Integer, ForeignKey('events.id')),
    Column('venue_id', Integer, ForeignKey('venues.id')))

venue_user_association = Table('user_venue', metadata,
    Column('user_id', Integer, ForeignKey('tg_user.user_id')),
    Column('venue_id', Integer, ForeignKey('venues.id')))

user_group_table = Table('user_group', metadata,
    Column('user_id', Integer, ForeignKey('tg_user.user_id',
        onupdate="CASCADE", ondelete="CASCADE")),
    Column('group_id', Integer, ForeignKey('tg_group.group_id',
        onupdate="CASCADE", ondelete="CASCADE")))

group_permission_table = Table('group_permission', metadata,
    Column('group_id', Integer, ForeignKey('tg_group.group_id',
        onupdate="CASCADE", ondelete="CASCADE")),
    Column('permission_id', Integer, ForeignKey('permission.permission_id',
        onupdate="CASCADE", ondelete="CASCADE")))
    
        
# identity model
class Venue(object):

    def __repr__(self):
        return self.venue_name

        
class Event(object):

    def __repr__(self):
        return 'Event: ' + self.event_name 

        
class EventTag(object):
        
    def __repr__(self):
        return 'Tag name: ' + self.tag_name
        
        
class Visit(object):

    """
    A visit to your site
    """
    def lookup_visit(cls, visit_key):
        return Visit.get(visit_key)
    lookup_visit = classmethod(lookup_visit)

    
class VisitIdentity(object):

    """
    A Visit that is link to a User object
    """
    pass

    
class Group(object):

    """
    An ultra-simple group definition.
    """
    pass

    
class User(object):

    """
    Reasonably basic User definition. Probably would want additional
    attributes.
    """
    def permissions(self):
        perms = set()
        for g in self.groups:
            perms = perms | set(g.permissions)
        return perms
    permissions = property(permissions)

    def by_email_address(klass, email):
        """
        A class method that can be used to search users
        based on their email addresses since it is unique.
        """
        return klass.get_by(users_table.c.email_address==email)

    by_email_address = classmethod(by_email_address)

    def by_user_name(klass, username):
        """
        A class method that permits to search users
        based on their user_name attribute.
        """
        return klass.get_by(users_table.c.user_name==username)
    by_user_name = classmethod(by_user_name)

    def _set_password(self, password):
        '''
        encrypts password on the fly using the encryption
        algo defined in the configuration
        '''
        self._password = identity.encrypt_password(password)

    def _get_password(self):
        '''
        returns password
        '''
        return self._password

    password = property(_get_password, _set_password)

    
class Permission(object):

    """
    A relationship that determines what each Group can do
    """
    pass

    
def assign(*args, **kw):
    """Map tables to objects with knowledge about the session context."""
    return assign_mapper(session.context, *args, **kw)

assign(Visit, visits_table)

assign(VisitIdentity, visit_identity_table,
    properties=dict(
        users=relation(User, backref='visit_identity')))
          
assign(User, users_table,
    properties=dict(
        _password=users_table.c.password,
        events=relation(Event),
        venues=relation(Venue, secondary=venue_user_association,
        backref='users')))
        
assign(Group, groups_table,
    properties=dict(
        users=relation(User,secondary=user_group_table,
        backref='groups')))
    
assign(Permission, permissions_table,
    properties=dict(
        groups=relation(Group,
        secondary=group_permission_table, backref='permissions')))
        
assign(Event, events_table, 
    properties=dict(
        tags=relation(EventTag, secondary=events_tags_association,
        backref='tagged_events')))

assign(EventTag, event_tags_table)

assign(Venue, venues_table, 
    properties=dict(
        events=relation(Event, secondary=event_venue_association,
        backref='venue')))        
